/*
 * Copyright 2012 Finbudget.com
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package finbudgettable.client.ui.grid.cell.currency;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.*;
import com.google.gwt.user.client.ui.*;

import finbudgettable.client.ui.grid.Utils;
import finbudgettable.client.ui.grid.column.FilterPanel;
import finbudgettable.client.ui.grid.filter.Filter;
import finbudgettable.client.ui.grid.filter.FilterChangeEvent;
import finbudgettable.client.ui.grid.filter.FilterChangeHandler;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

public class CurrencyFilterPanel extends VerticalPanel implements FilterPanel {

    interface FilterFactory {
        String getOp();
        Filter create(CurrencyFilterPanel filterPanel);
    }

    interface FilterPresenter {
        void show(CurrencyFilterPanel filterPanel, CurrencyFilter filter);
    }

    private static final FilterFactory equalFilterFactory =
            new FilterFactory() {
                @Override
                public String getOp() {
                    return "=";
                }

                @Override
                public Filter create(CurrencyFilterPanel filterPanel) {
                    return new EqualCurrencyFilter(filterPanel.fieldName, filterPanel.getCurrencyValue());
                }
            };

    private static final FilterPresenter equalFilterPresenter =
            new FilterPresenter() {
                @Override
                public void show(CurrencyFilterPanel filterPanel, CurrencyFilter filter) {
                    String op = equalFilterFactory.getOp();
                    if (filterPanel.setOperationByName(op)) {
                    	BigDecimal bd = filter.getValue();
                        filterPanel.textBox.setText(bd == null ? null : bd.toPlainString());
                    }
                }
            };

    private static final FilterFactory greaterFilterFactory =
            new FilterFactory() {
                @Override
                public String getOp() {
                    return ">";
                }

                @Override
                public Filter create(CurrencyFilterPanel filterPanel) {
                    return new GreaterCurrencyFilter(filterPanel.fieldName, filterPanel.getCurrencyValue());
                }
            };

    private static final FilterPresenter greaterFilterPresenter =
            new FilterPresenter() {
                @Override
                public void show(CurrencyFilterPanel filterPanel, CurrencyFilter filter) {
                    String op = greaterFilterFactory.getOp();
                    if (filterPanel.setOperationByName(op)) {
                        filterPanel.textBox.setText(filter.getValue() == null ? null : filter.getValue().toPlainString());
                    }
                }
            };

    private static final FilterFactory lessFilterFactory =
            new FilterFactory() {
                @Override
                public String getOp() {
                    return "<";
                }

                @Override
                public Filter create(CurrencyFilterPanel filterPanel) {
                    return new LessCurrencyFilter(filterPanel.fieldName, filterPanel.getCurrencyValue());
                }
            };

    private static final FilterPresenter lessFilterPresenter =
            new FilterPresenter() {
                @Override
                public void show(CurrencyFilterPanel filterPanel, CurrencyFilter filter) {
                    String op = lessFilterFactory.getOp();
                    if (filterPanel.setOperationByName(op)) {
                        filterPanel.textBox.setText(filter.getValue() == null ? null : filter.getValue().toPlainString());
                    }
                }
            };

    private static final FilterFactory notEqualFilterFactory =
            new FilterFactory() {
                @Override
                public String getOp() {
                    return "<>";
                }

                @Override
                public Filter create(CurrencyFilterPanel filterPanel) {
                    return new NotEqualCurrencyFilter(filterPanel.fieldName, filterPanel.getCurrencyValue());
                }
            };

    private static final FilterPresenter notEqualFilterPresenter =
            new FilterPresenter() {
                @Override
                public void show(CurrencyFilterPanel filterPanel, CurrencyFilter filter) {
                    String op = notEqualFilterFactory.getOp();
                    if (filterPanel.setOperationByName(op)) {
                        filterPanel.textBox.setText(filter.getValue() == null ? null : filter.getValue().toPlainString());
                    }
                }
            };

    private static final FilterFactory lessOrEqualFilterFactory =
            new FilterFactory() {
                @Override
                public String getOp() {
                    return "<=";
                }

                @Override
                public Filter create(CurrencyFilterPanel filterPanel) {
                    return new LessOrEqualCurrencyFilter(filterPanel.fieldName, filterPanel.getCurrencyValue());
                }
            };


    private static final FilterPresenter LessOrEqualFilterPresenter =
            new FilterPresenter() {
                @Override
                public void show(CurrencyFilterPanel filterPanel, CurrencyFilter filter) {
                    String op = lessOrEqualFilterFactory.getOp();
                    if (filterPanel.setOperationByName(op)) {
                        filterPanel.textBox.setText(filter.getValue() == null ? null : filter.getValue().toPlainString());
                    }
                }
            };


    private static final FilterFactory greaterOrEqualFilterFactory =
            new FilterFactory() {
                @Override
                public String getOp() {
                    return ">=";
                }

                @Override
                public Filter create(CurrencyFilterPanel filterPanel) {
                    return new GreaterOrEqualCurrencyFilter(filterPanel.fieldName, filterPanel.getCurrencyValue());
                }
            };

    private static final FilterPresenter greaterOrEqualFilterPresenter =
            new FilterPresenter() {
                @Override
                public void show(CurrencyFilterPanel filterPanel, CurrencyFilter filter) {
                    String op = lessOrEqualFilterFactory.getOp();
                    if (filterPanel.setOperationByName(op)) {
                        filterPanel.textBox.setText(filter.getValue() == null ? null : filter.getValue().toPlainString());
                    }
                }
            };

    private static final Strings STRINGS = GWT.create(Strings.class);
    private static final Map<String, FilterFactory> OPERATIONS = new HashMap<String, FilterFactory>();
    private static final Map<Class<?>, FilterPresenter> PRESENTERS = new HashMap<Class<?>, FilterPresenter>();
    private final ListBox listBox;
    private final TextBox textBox;
    private final String fieldName;

    static {
        OPERATIONS.put(equalFilterFactory.getOp(), equalFilterFactory);
        OPERATIONS.put(greaterFilterFactory.getOp(), greaterFilterFactory);
        OPERATIONS.put(lessFilterFactory.getOp(), lessFilterFactory);
        OPERATIONS.put(notEqualFilterFactory.getOp(), notEqualFilterFactory);
        OPERATIONS.put(lessOrEqualFilterFactory.getOp(), lessOrEqualFilterFactory);
        OPERATIONS.put(greaterOrEqualFilterFactory.getOp(), greaterOrEqualFilterFactory);
    }

    static {
        PRESENTERS.put(EqualCurrencyFilter.class, equalFilterPresenter);
        PRESENTERS.put(GreaterCurrencyFilter.class, greaterFilterPresenter);
        PRESENTERS.put(LessCurrencyFilter.class, lessFilterPresenter);
        PRESENTERS.put(NotEqualCurrencyFilter.class, notEqualFilterPresenter);
        PRESENTERS.put(LessOrEqualCurrencyFilter.class, LessOrEqualFilterPresenter);
        PRESENTERS.put(GreaterOrEqualCurrencyFilter.class, greaterOrEqualFilterPresenter);
    }


    public CurrencyFilterPanel(String fieldName) {
        this.fieldName = fieldName;
        Label filterLabel = new Label(STRINGS.filter());

        Label valueLabel = new Label(STRINGS.value());

        listBox = new ListBox();
        for (String op : OPERATIONS.keySet()) {
            listBox.addItem(op);
        }

        textBox = new TextBox();

        final Button applyButton = new Button(STRINGS.applyFilter());
        applyButton.setStyleName(Utils.blueButton);
        applyButton.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                BigDecimal value = getCurrencyValue();
                if (value != null) {
                    String op = listBox.getValue(listBox.getSelectedIndex());
                    fireEvent(new FilterChangeEvent(createFilter(op)));
                }
            }
        });

        textBox.addKeyDownHandler(new KeyDownHandler() {
            @Override
            public void onKeyDown(KeyDownEvent event) {
                if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
                    applyButton.click();
                }
            }
        });


        Grid grid = new Grid(3, 2);
        grid.setStyleName(CurrencyCell.RESOURCES.style().bCurrencyFilterPanel());
        grid.setWidget(0, 0, filterLabel);
        grid.setWidget(0, 1, listBox);
        grid.setWidget(1, 0, valueLabel);
        grid.setWidget(1, 1, textBox);
        grid.setWidget(2, 1, applyButton);

        add(grid);
    }

    private BigDecimal getCurrencyValue() {
        try {
            return new BigDecimal(textBox.getValue().replaceAll(",", "."));
        } catch (Exception ex) {
            return null;
        }
    }


    protected Filter createFilter(String op) {
        FilterFactory factory = OPERATIONS.get(op);
        return factory.create(this);
    }

    @Override
    public void setFilter(Filter filter) {
        if (filter != null && filter instanceof CurrencyFilter) {
            FilterPresenter presenter = PRESENTERS.get(filter.getClass());
            if (presenter != null) {
                presenter.show(this, (CurrencyFilter) filter);
                return;
            }
        }
        textBox.setText("");
        listBox.setSelectedIndex(0);
    }

    @Override
    public void addFilterChangeHandler(FilterChangeHandler handler) {
        addHandler(handler, FilterChangeEvent.TYPE);
    }

    private boolean setOperationByName(String op) {
        for (int i = 0; i < listBox.getItemCount(); i++) {
            if (op.equals(listBox.getValue(i))) {
                listBox.setSelectedIndex(i);
                return true;
            }
        }
        return false;
    }
}
